using System;

namespace MetaContainer
{
   /// <summary>
   /// Defines useful overload of <see cref="IMetaContainer"/> methods.
   /// </summary>
   public static class MetaContainerExtensions
   {
      /// <summary>
      /// Registers default (unnamed) mapping from service interface <typeparam name="TFrom"/> to implementation class
      /// <typeparam name="TTo"/> with transient lifestyle.
      /// </summary>
      /// <typeparam name="TFrom">Type of service interface.</typeparam>   
      /// <typeparam name="TTo">Type of service implementation.</typeparam>
      /// <param name="container">Container instance</param>   
      public static void Register<TFrom, TTo>(this IMetaContainer container) where TTo : TFrom
      {
         container.Register(typeof(TFrom), typeof(TTo), null, Scope.Transient);
      }

      /// <summary>
      /// Registers default (unnamed) mapping from service interface <typeparam name="TFrom"/> to implementation class
      /// <typeparam name="TTo"/> with <paramref name="scope"/> scope.
      /// </summary>      
      /// <typeparam name="TFrom">Type of service interface.</typeparam>   
      /// <typeparam name="TTo">Type of service implementation.</typeparam>
      /// <param name="container">Container instance</param>      
      /// <param name="scope">Scope or lifestyle of a component.</param>
      public static void Register<TFrom, TTo>(this IMetaContainer container, Scope scope) where TTo : TFrom
      {
         container.Register(typeof(TFrom), typeof(TTo), null, scope);
      }

      /// <summary>
      /// Registers mapping from service interface <typeparam name="TFrom"/> to implementation class
      /// <typeparam name="TTo"/> named <paramref name="name"/> and with <paramref name="scope"/> scope.
      /// </summary>      
      /// <typeparam name="TFrom">Type of service interface.</typeparam>   
      /// <typeparam name="TTo">Type of service implementation.</typeparam>
      /// <param name="container">Container instance.</param>
      /// <param name="name">Name of the mapping (if named, otherwise - null).</param>
      /// <param name="scope">Scope or lifestyle of a component.</param>
      public static void Register<TFrom, TTo>(this IMetaContainer container, string name, Scope scope) where TTo : TFrom
      {
         container.Register(typeof(TFrom), typeof(TTo), name, scope);
      }

      /// <summary>
      /// Registers default (unnamed) mapping from service interface <paramref name="from"/> to implementation class
      /// <paramref name="to"/> with transient lifestyle.
      /// </summary>
      /// <param name="container">Container instance.</param>
      /// <param name="from">Service interface type.</param>
      /// <param name="to">Service implementation type.</param>      
      public static void Register(this IMetaContainer container, Type from, Type to)
      {
         container.Register(from, to, null, Scope.Transient);
      }

      /// <summary>
      /// Registers mapping from service interface <paramref name="from"/> to implementation class
      /// <paramref name="to"/> named <paramref name="name"/> and with transient lifestyle.
      /// </summary>
      /// <param name="container">Container instance.</param>
      /// <param name="from">Service interface type.</param>
      /// <param name="to">Service implementation type.</param>
      /// <param name="name">Name of the mapping (if named, otherwise - null).</param>      
      public static void Register(this IMetaContainer container, Type from, Type to, string name)
      {
         container.Register(from, to, name, Scope.Transient);
      }

      /// <summary>
      /// Registers default (unnamed) mapping from service interface <paramref name="from"/> to implementation class
      /// <paramref name="to"/> with <paramref name="scope"/> scope.
      /// </summary>
      /// <param name="container">Container instance.</param>
      /// <param name="from">Service interface type.</param>
      /// <param name="to">Service implementation type.</param>      
      /// <param name="scope">Scope or lifestyle of a component.</param>
      public static void Register(this IMetaContainer container, Type from, Type to, Scope scope)
      {
         container.Register(from, to, null, scope);
      }

      /// <summary>
      /// Registers default (unnamed) mapping from service interface <typeparam name="TFrom"/> to a method <paramref name="factoryMethod"/> producing
      /// service implementation objects. Mapping has transient scope.
      /// </summary>      
      /// <typeparam name="TFrom">Type of service interface.</typeparam>
      /// <param name="container">Container instance.</param>
      /// <param name="factoryMethod">A method producing service implementations.</param>      
      public static void Register<TFrom>(this IMetaContainer container, Func<string, TFrom> factoryMethod)
      {
         container.Register(typeof(TFrom), x => factoryMethod(x), Scope.Transient);
      }

      /// <summary>
      /// Registers default (unnamed) mapping from service interface <typeparam name="TFrom"/> to a method <paramref name="factoryMethod"/> producing
      /// service implementation objects. Mapping is defined with
      /// <paramref name="scope"/> scope.
      /// </summary>      
      /// <typeparam name="TFrom">Type of service interface.</typeparam>
      /// <param name="container">Container instance.</param>
      /// <param name="factoryMethod">A method producing service implementations.</param>      
      /// <param name="scope">Scope or lifestyle of a component.</param>
      public static void Register<TFrom>(this IMetaContainer container, Func<string, TFrom> factoryMethod, Scope scope)
      {
         container.Register(typeof(TFrom), x => factoryMethod(x), scope);
      }      
      
      /// <summary>
      /// Gets instance of service <typeparamref name="TFrom"/>.
      /// </summary>
      /// <typeparam name="TFrom">Type of service interface.</typeparam>
      /// <param name="container">Container interface.</param>
      /// <returns>Instance of a service.</returns>
      public static TFrom Resolve<TFrom>(this IMetaContainer container)
      {
         return container.GetInstance<TFrom>();
      }
   }
}